/**
 * Copyright 2009 cestum.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cestum.cave.presenter.wave {
import com.hurlant.math.BigInteger;

import flash.utils.ByteArray;

import org.cestum.cave.presenter.wave.utils.HashedVersionFactoryImpl;
import org.waveprotocol.wave.model.id.WaveletName;
import org.waveprotocol.wave.protocol.ProtocolAppliedWaveletDelta;

/**
 * A {@link WaveletDelta}'s version along with a hash of the preceding history.
 * For fake deltas that do not contain the correct hash, use
 * {@link #unsigned(long)}.
 *
 * This is an immutable value class and therefore thread safe.
 *
 *
 */
public final class HashedVersion {
  /** Same as unsigned(0). */
  public static var UNSIGNED_VERSION_0:HashedVersion= unsigned(new BigInteger("0"));

  private static var HASHED_HISTORY_VERSION_FACTORY:HashedVersionFactory =
    new HashedVersionFactoryImpl();

  private var version:BigInteger;
  private var historyHash:ByteArray;

  /**
   * Constructs a hashed version with the specified version and historyHash.
   */
  public function HashedVersion(version:BigInteger, historyHash:ByteArray) {
    if (historyHash == null) {
      throw new Error("null historyHash");
    } else {
      this.version = version;
      this.historyHash = historyHash;
    }
  }

  /**
   * Constructs a HashedVersion representing version 0 of the specified wavelet.
   */
  public static function versionZero(waveletName:WaveletName):HashedVersion {
    // TODO: Why not inline that method here and get rid of the class?
    return HASHED_HISTORY_VERSION_FACTORY.createVersionZero(waveletName);
  }

  /**
   * Constructs an unhashed (i.e. unsigned) version with only a version number
   * and some fake hash. This may be used when we don't rely on hashes
   * for authentication and error checking.
   */
  public static function unsigned(version:BigInteger):HashedVersion {
    return new HashedVersion(version, new ByteArray());
  }

  /**
   * Get the hashed version an applied delta was applied at.
   */
  public static function getHashedVersionAppliedAt(appliedDelta:ByteStringMessage):HashedVersion {
    if ((ProtocolAppliedWaveletDelta(appliedDelta.getMessage())).hasHashedVersionAppliedAt) {
//      return 
//	  	WaveletOperationSerializer.deserialize((ProtocolAppliedWaveletDelta(appliedDelta.getMessage()))
//          .getHashedVersionAppliedAt());
    }
//	else {
//      try {
//        var innerDelta:ProtocolWaveletDelta= ProtocolWaveletDelta.parseFrom((ProtocolAppliedWaveletDelta(appliedDelta.getMessage())).getSignedOriginalDelta().getDelta());
//        return WaveletOperationSerializer.deserialize(innerDelta.getHashedVersion());
//      } catch (e) {
//        throw new Error(e);
//      }
//    }
	return null;
  }

  /**
   * Get the hashed version after an applied delta is applied.
   */
  public static function getHashedVersionAfter(
      appliedDelta:ByteStringMessage):HashedVersion {
//    var opsApplied:int= (ProtocolAppliedWaveletDelta(appliedDelta.getMessage())).getOperationsApplied();
//    var versionAppliedAt:HashedVersion= getHashedVersionAppliedAt(appliedDelta);
//    return new HashedVersionFactoryImpl().create(
//        appliedDelta.getByteString(), versionAppliedAt, opsApplied);
	  return null;
  }

  /** The number of ops that lead to this version. */
  public function getVersion():BigInteger {
    return version;
  }

  /** A hash over the entire history of ops up to this version. */
  public function getHistoryHash():ByteArray {
    return historyHash;
  }

  
//  public function hashCode():int {
//    var result:int= 17;
//    result = 31* result + Long.valueOf(version).hashCode();
//    result = 31* result + historyHash.hashCode();
//    return result;
//  }

  
//  public function equals(obj:Object):Boolean {
//    if (!(obj instanceof HashedVersion)) {
//      return false;
//    } else {
//      var that:HashedVersion= HashedVersion(obj);
//      return version == that.version && Arrays.equals(historyHash, that.historyHash);
//    }
//  }

  
//  public function toString():String {
////    return Long.toString(version) + ":" + new String(Hex.encodeHex(historyHash));
//  }
}
}